package com.kongjs.online.preview.utils;

import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.conversion.msoffice.MicrosoftPowerpointBridge;
import com.documents4j.job.LocalConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.file.Files;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class Documents4jUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(Documents4jUtils.class);
    /* IConverter converter = LocalConverter.builder()
                .baseFolder(new File("C:\\Users\\documents4j\\temp"))
                .workerPool(20, 25, 2, TimeUnit.SECONDS)
                .processTimeout(5, TimeUnit.SECONDS)
                .build();*/

    /*IConverter converter = RemoteConverter.builder()
            .baseFolder(new File("C:\Users\documents4j\temp"));
                       .workerPool(20, 25, 2, TimeUnit.SECONDS)
            .requestTimeout(10, TimeUnit.SECONDS)
            .baseUri("http://localhost:9998");
                       .build();*/
    /*
     * cancel()：如果等太久，你可以直接取消这个任务
     * isCancelled()：任务是不是已经取消了
     * isDone()：任务是不是已经完成了
     * get()：有2个get()方法，不带参数的表示无穷等待，或者你可以只等待给定时间
     * mayInterruptIfRunning为true，该task正在执行，这个task应该被中断;
     * mayInterruptIfRunning为false，该task正在执行，这个task将会继续执行到完成。
     */
    /*
     *ExecutionException封装了正在执行的线程抛出的任何异常，所以如果线程是做某种IO导致抛出IOException异常的，那么它会被包装在一个ExecutionException中并被重新抛出。
     *InterruptedException不是任何出错的迹象。在那里给你一种让你的线程知道什么时候停止的方法，以便他们完成当前的工作并优雅地退出。
     */
    public static void converter(File tempDir, DocumentType sourceType, File source, DocumentType targetType, File target) {
        LOGGER.info("临时目录: [" + tempDir + "] sourceType: [" + sourceType + "] source: [" + source + "] targetType: [" + targetType + "] target: [" + target + "]");
        // 性能配置
        int processors = Runtime.getRuntime().availableProcessors();
        int corePoolSize = processors * 4;
        int maximumPoolSize = processors * 16;
        int keepAliveTime = 3;
        int processTimeout = 5;
        IConverter converter = null;
        LOGGER.info("转换开始 LocalConverter");
        try {
            converter = LocalConverter
                    .builder()
                    .baseFolder(tempDir)
                    .workerPool(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS)
                    .processTimeout(processTimeout, TimeUnit.SECONDS)
                    .build();
            Future<Boolean> booleanFuture = converter
                    .convert(source)
                    .as(sourceType)
                    .to(target)
                    .as(targetType)
                    .prioritizeWith(1000)
                    .schedule();
            try {
                Boolean aBoolean = booleanFuture.get(10, TimeUnit.SECONDS);
                LOGGER.info("转换线程状态 " + aBoolean);
            } catch (InterruptedException e) {
                LOGGER.error("转换线程中断" + source.getName() + " ==> " + target.getName(), e);
            } catch (ExecutionException e) {
                LOGGER.error("转换线程异常 " + source.getName() + " ==> " + target.getName(), e);
            } catch (TimeoutException e) {
                booleanFuture.cancel(true);
                LOGGER.error("转换线程超时 " + source.getName() + " ==> " + target.getName(), e);
            } finally {
                if (booleanFuture.isCancelled()) {
                    LOGGER.error("转换线程取消 " + source.getName() + " ==> " + target.getName());
                }
                if (booleanFuture.isDone()) {
                    LOGGER.info("转换线程结束 " + source.getName() + " ==> " + target.getName());
                }
            }
        } catch (Exception e) {
            LOGGER.error("转换异常", e);
        } finally {
            if (converter != null) {
                converter.shutDown();
            }
        }
    }

    public static void converter(File tempDir, File source, File target) {
        if (Files.notExists(tempDir.toPath())) {
            try {
                Files.createDirectories(tempDir.toPath());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        DocumentType sourceType = getType(source);
        DocumentType targetType = getType(target);
        converter(tempDir, sourceType, source, targetType, target);
    }

    public static void converter(File source, File target) {
        File tempDir = new File("C:\\Windows\\Temp");
        converter(tempDir, source, target);
    }

    public static void exec(String... cmd) {
        System.out.println("当前进程的工作空间:" + System.getProperty("user.dir"));
        try {
            ProcessBuilder pb = new ProcessBuilder()
                    .command(cmd);
            Process process = pb.start();
            System.out.println("当前进程的工作空间:" + System.getProperty("user.dir"));
            print(process.getInputStream());
            print(process.getErrorStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void print(InputStream is) {
        String encoding = System.getProperty("sun.jnu.encoding");
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is, encoding));) {
            for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) {
                System.out.println(line);
            }
        } catch (IOException ignored) {
        }
    }

    public static void killWord() {
        String killWord = "taskkill /f /t /im winword.exe";
        exec(killWord);
    }

    public static void killExcel() {
        String killExecel = "taskkill /f /t /im execel.exe";
        exec(killExecel);
    }

    public static void killPpt() {
        String killPowerpnt = "taskkill /f /t /im powerpnt.exe";
        exec(killPowerpnt);
    }

    public static void main(String[] args) {
    }

    /*
     * 文件后缀
     * */
    public static String getSuffix(File file) {
        String fileName = file.getName();
        int lastIndexOf = fileName.lastIndexOf(".");
        String suffix = null;
        if (lastIndexOf != -1) {
            suffix = fileName.substring(lastIndexOf + 1);
        }
        return suffix;
    }

    /*
       支持的类型
       DocumentType.MS_WORD
       DocumentType.DOCX
       DocumentType.DOC
       DocumentType.MS_EXCEL
       DocumentType.XLSX
       DocumentType.XLTX
       DocumentType.XLS
       DocumentType.ODS
       DocumentType.OTS
       DocumentType.CSV
       DocumentType.XML
       DocumentType.MHTML
       DocumentType.HTML
       DocumentType.PDF
       DocumentType.PDFA
       DocumentType.TEXT
       DocumentType.MS_POWERPOINT
       DocumentType.PPTX
       DocumentType.PPT
    */
    /*
     * 常用文件类型
     * */
    public static DocumentType getType(File file) {
        String suffix = getSuffix(file);
        if (suffix.equalsIgnoreCase("docx")) {
            return DocumentType.DOCX;
        } else if (suffix.equalsIgnoreCase("doc")) {
            return DocumentType.DOC;
        } else if (suffix.equalsIgnoreCase("xlsx")) {
            return DocumentType.XLSX;
        } else if (suffix.equalsIgnoreCase("xls")) {
            return DocumentType.XLS;
        } else if (suffix.equalsIgnoreCase("pptx")) {
            return DocumentType.PPTX;
        } else if (suffix.equalsIgnoreCase("ppt")) {
            return DocumentType.PPT;
        } else if (suffix.equalsIgnoreCase("html")) {
            return DocumentType.HTML;
        } else if (suffix.equalsIgnoreCase("pdf")) {
            return DocumentType.PDF;
        } else if (suffix.equalsIgnoreCase("xml")) {
            return DocumentType.XML;
        } else if (suffix.equalsIgnoreCase("csv")) {
            return DocumentType.CSV;
        } else if (suffix.equalsIgnoreCase("txt")) {
            return DocumentType.TEXT;
        }
        return null;
    }
}
